;(function(global,factory){
    typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory(
            require('jquery')
            ,require('ztree')
            ,require('ztree.excheck')
            ,require('ztree.exhide')
        )
        : typeof define === 'function' && define.amd ? define(['jquery','ztree','ztree.excheck','ztree.exhide'],factory)
        : global.layui && layui.define ?
            layui.define(['jquery','ztree','ztree.excheck','ztree.exhide'],function (exports) {
                let $ = layui.jquery
                exports('ShuttleFlow',factory($));
            })
        : (global.ShuttleFlow = factory($));
})(this,function($) {
    let style = document.createElement('style')
    ,styleText = [
        '.ck-shuttle-flow .shuttle-flow-left,.ck-shuttle-flow .shuttle-flow-right{background-color: #F7F7F7;height: 460px;width: 300px;}',
        '.ck-shuttle-flow .shuttle-flow-center{width: 100px;height: 460px;}.ck-shuttle-flow{white-space: nowrap;}',
        '.ck-shuttle-flow .operate-flow{text-align: center;transform: translate(0,-50%);position: relative;top: 50%;}',
        '.ck-shuttle-flow .shuttle-flow-left .layui-form-item{margin: 0}.ck-shuttle-flow .shuttle-flow-left .layui-input-block{margin: 0;padding: 8px;position: relative}',
        '.ck-shuttle-flow .shuttle-flow-left .layui-input{padding-right: 25px}.ck-shuttle-flow .shuttle-flow-tree-container{overflow-x:hidden;}',
        '.ck-shuttle-flow .shuttle-flow-tree-container-hassearch{height: calc(100% - 52px);}.ck-shuttle-flow .shuttle-flow-tree-container-nosearch {height: 100%;}',
        '.ck-shuttle-flow .layui-icon-search{position: absolute;right: 15px;top: 18px;}.ck-shuttle-flow .ztree{max-height: 100%;}.ck-shuttle-flow .operate-flow-btn-container{padding: 8px}',
        '.shuttle-flow-loading{position: absolute;left: 0;right: 0;bottom: 0;top: 0;-webkit-perspective: 600;perspective: 600;display: flex;align-items: center;justify-content: center;background-color: #fff}',
        '.shuttle-flow-loading svg{width: 140px;height: 140px;}.shuttle-checkbox{display: none; }',
        '.shuttle-cell-checkbox{text-align: center;margin-left: -9px;}',
        '.shuttle-show-checkbox{display: inline-block;font-size: 0;height: auto!important;line-height: normal!important;min-width: 18px;min-height: 18px;border: none!important;margin-right: 0;padding-right: 0;background: 0 0;cursor: pointer;}',
        '.shuttle-show-checkbox label.shuttle-icon{margin:0;display: block;width: 18px;height: 18px;position: relative;border-radius: 2px;overflow: hidden;box-sizing: border-box;border: 1px solid #d2d2d2;}',
        '.shuttle-show-checkbox label.shuttle-icon:hover{border: 1px solid #E3BE66;}',
        '.shuttle-show-checkbox .shuttle-icon-ok::before{content: \'\\2713\';position: absolute;left: 0;right: 0;top: 0;bottom: 0;width: 1.3em;text-align: center;font-size: 14px;line-height: 18px;color: #fff;background-color: #E3BE66;}',
        '.shuttle-table table{border-collapse: separate;border-spacing: 0;width: 100%;font-size: 14px;}',
        '.shuttle-table-cell{text-align: left;overflow: hidden;text-overflow: ellipsis}',
        '.table-cell-center{text-align:center !important;}.shuttle-table-thead{background-color: #fafafa;border: 1px solid #f0f0f0;}',
        '.shuttle-table-thead tr>th, .shuttle-table-tbody tr>td{padding: 5px;}.shuttle-table-body{overflow-x: hidden;}',
        '.shuttle-show-checkbox .shuttle-icon-ok{border: 0 !important;}',
        '.shuttle-table,.shuttle-table-scroll{height:100%}'
    ].join("");
    style.innerHTML = styleText;
    document.getElementsByTagName('body')[0].appendChild(style);
    //ShuttleFlow配置
    let dftSetting = {
        moutEl: ''
        ,contextPath:'/'
        , searchInput: {
            enable: false
            , id: 'key-node'
            , name: 'keyword'
            , placeholder: '请输入关键词'
        }
        , isEnableLoading:false
        , useCusIcon: true
        , data: null
        , events: {
            beforeAddEvt(addBtnEl,treeObj,checkedNodes) {
                return checkedNodes.filter(node=>{
                    return node.type == 1
                })
            }
            ,addEvt(addBtnEl,treeObj,checkedNodes) {
                return checkedNodes;
            }
            ,beforeRemove(removeBtnEl,treeObj,checkedNodes){

            }
            ,removeEvt(removeBtnEl,treeObj,checkedNodes){

            }
        }
        , table:{
            tableId:'shuttle-data-table'
            ,height:'full-31'
            ,removeKey:'id'
            ,cols:[
                {type:'checkbox', width:60,align:'center'}
                ,{field:'depart',title:'部门',template(rowData,i,treeObj){
                    let treeNode = treeObj.getNodeByParam("id",rowData.id)
                    ,parentNode = treeNode.getParentNode();
                    let parNode = $.extend({},parentNode);
                    delete parNode.children;
                    parNode.userName = parNode.name;
                    parNode.userId = parNode.id;
                    rowData.parentNode = parNode
                    if(parentNode){
                        return parentNode.name||'';
                    }
                    return '';
                 }}
                ,{field:'name',title:'姓名'}
            ]
        }
        //ztree配置
        , ztree: {
            treeId: "shuttle-flow-tree"
            , view: {
                selectedMulti: false //按住ctrl是否可以多选
                ,showIcon:function(treeId, treeNode){
                    if(treeNode.type && treeNode.type == 1){
                        return false
                    }
                    return true;
                }
            }
            , check: {
                enable: true
                , chkStyle: 'checkbox'
                //,chkboxType:{ "Y": "", "N": "" }
            }
            , data: {
                simpleData: {
                    enable: false
                }
            }
            , async: {
                enable: false
                , url: ''
                , dataType:'json'
                , otherParam: null
                , dataFilter:null
            }
            , callback: {
                onClick: null
                , onCheck: null
                , onAsyncSuccess: null
            }
        }
    }
    , ShuttleFlow = function (options) {
        this.options = $.extend(true, {}, dftSetting, options);
        this.moutEl = ShuttleFlow.utils.isDOMEl(options.moutEl) ? options.moutEl : document.querySelector(options.moutEl)
        this.tableData = [];
        this.ready()
    }
    ShuttleFlow.utils = {
        isDOMEl: typeof HTMLElement === 'object'
        ? function (obj) {return obj instanceof HTMLElement;}
        : function (obj) {return obj && typeof obj === 'object' && obj.nodeType === 1 && typeof obj.nodeName === 'string';}
        //订阅容器
        ,subEvents:{}
        //发布订阅模式
        ,pubSubObj(){
            let _self = this;
            //订阅方法subscribe 类似于on / watcher
            let subscribe = function(eventType,handle){
                !(eventType in _self.subEvents) && (_self.subEvents[eventType] = [])
                 _self.subEvents[eventType].push(handle);
            }
            //发布函数publish 类似于trigger / observe
            //data是数组
            , publish = function(eventType, data){
                eventType = _self.subEvents[eventType];
                for (let i = 0; i < eventType.length; i++) {
                    eventType[i].apply(null, data||[]);
                }
            }
            //删除全部订阅
            , unSubscribe = function(eventType) {
                 _self.subEvents[eventType] && delete _self.subEvents[eventType]
            }
            //通过handle删除指定订阅
            , unSubscribeByFun = function(eventType,handle){
                eventType = _self.subEvents[eventType];
                if (eventType) {
                    let handleIndex = eventType.indexOf(handle);
                    if (handleIndex >= 0) {
                        eventType.splice(handleIndex, 1);
                    }
                }
            }
            return {subscribe, publish, unSubscribe, unSubscribeByFun};
        }
        //加载动画
        ,loading(desc){
            return [
                '<svg version="1.1" id="dc-spinner" xmlns="http://www.w3.org/2000/svg" x="0px" y="0px" width:"240" height:"240" viewBox="0 0 38 38">'
                ,'<text x="14" y="21" font-family="Monaco" font-size="2px" style="letter-spacing:0.6" fill="grey">'+(desc||'LOADING')+'<animate attributeName="opacity" values="0;1;0" dur="1.8s" repeatCount="indefinite"/></text>'
                ,'<path fill="#373a42" d="M20,35c-8.271,0-15-6.729-15-15S11.729,5,20,5s15,6.729,15,15S28.271,35,20,35z M20,5.203 C11.841,5.203,5.203,11.841,5.203,20c0,8.159,6.638,14.797,14.797,14.797S34.797,28.159,34.797,20 C34.797,11.841,28.159,5.203,20,5.203z"></path>'
                ,'<path fill="#373a42" d="M20,33.125c-7.237,0-13.125-5.888-13.125-13.125S12.763,6.875,20,6.875S33.125,12.763,33.125,20 S27.237,33.125,20,33.125z M20,7.078C12.875,7.078,7.078,12.875,7.078,20c0,7.125,5.797,12.922,12.922,12.922 S32.922,27.125,32.922,20C32.922,12.875,27.125,7.078,20,7.078z"></path>'
                ,'<path fill="#2AA198" stroke="#2AA198" stroke-width="0.6027" stroke-miterlimit="10" d="M5.203,20 c0-8.159,6.638-14.797,14.797-14.797V5C11.729,5,5,11.729,5,20s6.729,15,15,15v-0.203C11.841,34.797,5.203,28.159,5.203,20z">'
                ,'<animateTransform attributeName="transform" type="rotate" from="0 20 20" to="360 20 20" calcMode="spline" keySplines="0.4, 0, 0.2, 1" keyTimes="0;1" dur="2s" repeatCount="indefinite" />'
                ,'</path><path fill="#859900" stroke="#859900" stroke-width="0.2027" stroke-miterlimit="10" d="M7.078,20 c0-7.125,5.797-12.922,12.922-12.922V6.875C12.763,6.875,6.875,12.763,6.875,20S12.763,33.125,20,33.125v-0.203 C12.875,32.922,7.078,27.125,7.078,20z">'
                ,'<animateTransform attributeName="transform" type="rotate" from="0 20 20" to="360 20 20" dur="1.8s" repeatCount="indefinite" /></path></svg>'
            ].join('')
        }
        //判断元素是否有滚动条
        ,getScrollWidth(el,redirect){
            redirect = redirect ? redirect : 'x'
            if(redirect != 'x' && redirect != 'y'){return;}
            let attr = {
                'x':'Width'
                ,'y':'Height'
            }
            let clientWidth = el ? el['client'+attr[redirect]] : document.documentElement['client'+attr[redirect]] || document.body['client'+attr[redirect]];
            let scrollWidth = el ? el['offset'+attr[redirect]] : window['inner'+attr[redirect]];
            return scrollWidth - clientWidth;
        }
        ,parentSubTree(nodes){
            let nodePoint = {},newNodes = [];
            nodes.forEach(node=>{
                node.children && delete node.children;
            });
            nodes.forEach(node=>{
                nodePoint[node.id] = node
            })
            nodes.forEach((node,i)=>{
                if(node.pId in nodePoint){//if(nodePoint[node.pid])
                    (nodePoint[node.pId].children || (nodePoint[node.pId].children = [])).push(node);
                }else{//不在则是顶级节点
                    newNodes.push(node);
                }
            });
            return newNodes;
        }
        //模糊查询
        ,fuzzySearch(zTreeId, searchField, isHighLight, isExpand){
            var zTreeObj = $.fn.zTree.getZTreeObj(zTreeId);//get the ztree object by ztree id
            if(!zTreeObj){
                alert("fail to get ztree object");
            }
            var nameKey = zTreeObj.setting.data.key.name; //get the key of the node name
            isHighLight = isHighLight===false?false:true;//default true, only use false to disable highlight
            isExpand = isExpand?true:false; // not to expand in default
            zTreeObj.setting.view.nameIsHTML = isHighLight; //allow use html in node name for highlight use

            var metaChar = '[\\[\\]\\\\\^\\$\\.\\|\\?\\*\\+\\(\\)]'; //js meta characters
            var rexMeta = new RegExp(metaChar, 'gi');//regular expression to match meta characters

            // keywords filter function
            function ztreeFilter(zTreeObj,_keywords,callBackFunc) {
                if(!_keywords){
                    _keywords =''; //default blank for _keywords
                }

                // function to find the matching node
                function filterFunc(node) {
                    if(node && node.oldname && node.oldname.length>0){
                        node[nameKey] = node.oldname; //recover oldname of the node if exist
                    }
                    zTreeObj.updateNode(node); //update node to for modifications take effect
                    if (_keywords.length == 0) {
                        //return true to show all nodes if the keyword is blank
                        zTreeObj.showNode(node);
                        zTreeObj.expandNode(node,isExpand);
                        return true;
                    }
                    //transform node name and keywords to lowercase
                    if (node[nameKey] && node[nameKey].toLowerCase().indexOf(_keywords.toLowerCase())!=-1) {
                        if(isHighLight){ //highlight process
                            //a new variable 'newKeywords' created to store the keywords information
                            //keep the parameter '_keywords' as initial and it will be used in next node
                            //process the meta characters in _keywords thus the RegExp can be correctly used in str.replace
                            var newKeywords = _keywords.replace(rexMeta,function(matchStr){
                                //add escape character before meta characters
                                return '\\' + matchStr;
                            });
                            node.oldname = node[nameKey]; //store the old name
                            var rexGlobal = new RegExp(newKeywords, 'gi');//'g' for global,'i' for ignore case
                            //use replace(RegExp,replacement) since replace(/substr/g,replacement) cannot be used here
                            node[nameKey] = node.oldname.replace(rexGlobal, function(originalText){
                                //highlight the matching words in node name
                                var highLightText =
                                    '<span style="color: whitesmoke;background-color: darkred;">'
                                    + originalText
                                    +'</span>';
                                return 	highLightText;
                            });
                            zTreeObj.updateNode(node); //update node for modifications take effect
                        }
                        zTreeObj.showNode(node);//show node with matching keywords
                        return true; //return true and show this node
                    }

                    zTreeObj.hideNode(node); // hide node that not matched
                    return false; //return false for node not matched
                }

                var nodesShow = zTreeObj.getNodesByFilter(filterFunc); //get all nodes that would be shown
                processShowNodes(nodesShow, _keywords);//nodes should be reprocessed to show correctly
            }

            /**
             * reprocess of nodes before showing
             */
            function processShowNodes(nodesShow,_keywords){
                if(nodesShow && nodesShow.length>0){
                    //process the ancient nodes if _keywords is not blank
                    if(_keywords.length>0){
                        $.each(nodesShow, function(n,obj){
                            var pathOfOne = obj.getPath();//get all the ancient nodes including current node
                            if(pathOfOne && pathOfOne.length>0){
                                //i < pathOfOne.length-1 process every node in path except self
                                for(var i=0;i<pathOfOne.length-1;i++){
                                    zTreeObj.showNode(pathOfOne[i]); //show node
                                    zTreeObj.expandNode(pathOfOne[i],true); //expand node
                                }
                            }
                        });
                    }else{ //show all nodes when _keywords is blank and expand the root nodes
                        var rootNodes = zTreeObj.getNodesByParam('level','0');//get all root nodes
                        $.each(rootNodes,function(n,obj){
                            zTreeObj.expandNode(obj,true); //expand all root nodes
                        });
                    }
                }
            }

            //listen to change in input element
            $(searchField).bind('input propertychange', function() {
                var _keywords = $(this).val();
                searchNodeLazy(_keywords); //call lazy load
            });

            var timeoutId = null;
            var lastKeyword = '';
            // excute lazy load once after input change, the last pending task will be cancled
            function searchNodeLazy(_keywords) {
                if (timeoutId) {
                    //clear pending task
                    clearTimeout(timeoutId);
                }
                timeoutId = setTimeout(function() {
                    if (lastKeyword === _keywords) {
                        return;
                    }
                    ztreeFilter(zTreeObj,_keywords); //lazy load ztreeFilter function
                    // $(searchField).focus();//focus input field again after filtering
                    lastKeyword = _keywords;
                }, 500);
            }
        }
        ,uniArr(targetArr,newArr,compareRule){
            for(let i = 0; i<newArr.length; i++){
                if(targetArr.indexOf(newArr[i])>-1){
                    newArr.splice(i,1)
                    i--;
                }
            }
            return targetArr.concat(newArr);
        }
    }
    ShuttleFlow.prototype = {
        constructor: ShuttleFlow
        , ready() {
            this.renderShuttleFlow();
            this.rendered();
        }
        , renderShuttleFlow() {
            let options = this.options
            , treeId = options.ztree.treeId = options.ztree.treeId ? options.ztree.treeId : 'shuttle-flow-tree'
            , tableId = options.table.tableId = options.table.tableId ? options.table.tableId : 'shuttle-data-table'
            , searchInput = options.searchInput
            , shuttleFlowHeight = ' shuttle-flow-tree-container-nosearch'
            searchInput.id = searchInput.id || 'key-node'
            searchInput.name = searchInput.name || 'keyword'
            if(searchInput.enable){
                shuttleFlowHeight = ' shuttle-flow-tree-container-hassearch'
            }
            let html = '<div class="ck-shuttle-flow">'
                    html += '<div class="layui-inline shuttle-flow-left">'
                    if(searchInput.enable){
                        html += '<div class="layui-form">'
                            html += '<div class="layui-form-item">'
                                html += '<div class="layui-input-block"><i class="layui-icon layui-icon-search"></i><input id="' + searchInput.id+ '" name="'+searchInput.name+'" type="text" placeholder="' + searchInput.placeholder +'"  autocomplete="off" class="layui-input"></div>'
                            html += '</div>'
                        html += '</div>'
                    }
                        html += '<div class="shuttle-flow-tree-container'+shuttleFlowHeight+'"><div class="ztree" id="'+treeId+'"></div></div>'
                    html += '</div>'
                    html += '<div class="layui-inline shuttle-flow-center">'
                        html += '<div class="operate-flow">'
                            html += '<div class="operate-flow-btn-container">'
                                html += '<button type="button" class="operate-flow-add-btn layui-btn layui-btn-primary layui-btn-sm">添加<i class="layui-icon" style="margin: 8px">&#xe65b;</i></button>'
                            html += '</div>'
                            html += '<div class="operate-flow-btn-container">'
                                html += '<button type="button" class="operate-flow-remove-btn layui-btn layui-btn-primary layui-btn-sm"><i class="layui-icon" style="margin: 8px">&#xe65a;</i>移除</button>'
                            html += '</div>'
                        html += '</div>'
                    html += '</div>'
                    html += '<div class="layui-inline shuttle-flow-right"><table id="'+tableId+'" style="display: none"></table></div>'
            html +='</div>';
            if(options.isEnableLoading){
                html += '<div class="shuttle-flow-loading">'+ShuttleFlow.utils.loading()+'</div>'
            }
            this.moutEl.innerHTML = html;
        }
        , rendered() {
            this.setIcon();
            this.setAsyncSuc();
            this.setClick();
            this.setCheck()
            this.initZtree();
            this.fuzzySearch();
            this.evtsBind();
        }
        //初始化ztree
        , initZtree() {
            let options = this.options
                , ztreeSetting = options.ztree
            if (ztreeSetting.async.enable) {
                $.fn.zTree.init($("#" + ztreeSetting.treeId), options.ztree);
            } else {
                $.fn.zTree.init($("#" + ztreeSetting.treeId), options.ztree, options.data);
            }
        }
        //给'添加、移除按钮绑定事件'
        , evtsBind() {
            let _self = this
            , options = _self.options
            , moutEl = _self.moutEl
            , events = options.events
            , treeObj = $.fn.zTree.getZTreeObj(options.ztree.treeId)
            $(moutEl).on('click', '.operate-flow-add-btn', function () {
                let checkedNodes = treeObj.getCheckedNodes(true);
                let nodes = typeof events.beforeAddEvt == 'function' && events.beforeAddEvt.call(_self, this,treeObj,checkedNodes);
                //禁止触发添加事件
                if(nodes === false){return}
                //禁止默认行为
                nodes = typeof events.addEvt == 'function' && events.addEvt.call(_self, this,treeObj,nodes);
                if(nodes === false){return;}
                _self.addRow(nodes,treeObj);
            })
            $(moutEl).on('click', '.operate-flow-remove-btn', function () {
                let isExec = typeof events.beforeRemove == 'function' && events.beforeRemove.call(_self, this,treeObj);
                //禁止触发添加事件
                if (isExec === false) {return}
                //禁止默认行为
                isExec = typeof events.removeEvt == 'function' && events.removeEvt.call(_self, this,treeObj);
                if (isExec === false) {return;}
                _self.removeRow(treeObj);
            })
            $(moutEl).find('#'+options.table.tableId).parent().on('click', '.shuttle-show-checkbox', function () {
                let $this = $(this)
                , $table = $('#'+options.table.tableId) && $('#'+options.table.tableId).next()
                , $checkbox = $this.prev()
                , checked = $checkbox.prop('checked')
                , toggleChecked = function ($els, checked) {
                    if (checked) {
                        $els.removeClass('shuttle-checked').children('.shuttle-icon').removeClass('shuttle-icon-ok')
                    } else {
                        $els.addClass('shuttle-checked').children('.shuttle-icon').addClass('shuttle-icon-ok')
                    }
                }
                , $firstTds = $table.find('.shuttle-table-body').find('tr').find('td:first')
                , $tbodyCheckboxs = $firstTds.find('.shuttle-checkbox')
                $checkbox.prop('checked', !checked)
                toggleChecked($this, checked)
                if ($this.hasClass('shuttle-checkall')) {
                    $tbodyCheckboxs.prop('checked', !checked);
                    toggleChecked($firstTds.find('.shuttle-show-checkbox'), checked)
                    return;
                }
                let $tbodyCheckeds = $firstTds.find('.shuttle-checkbox:checked')
                , $allChecked = $table.find(".shuttle-checkall").prev()
                , allCheckedStatus = $allChecked.prop('checked');
                allCheckedStatus = $tbodyCheckeds.length < $tbodyCheckboxs.length ? false : true
                $allChecked.prop('checked', allCheckedStatus);
                toggleChecked($table.find(".shuttle-checkall"),!allCheckedStatus);
            })
        }
        //添加行到列表中
        ,addRow(rowsData,treeObj){
            let options = this.options
            //如果存在模糊查询
            if($("#"+options.searchInput.id).val()){
                this.tableData = ShuttleFlow.utils.uniArr(this.tableData,rowsData)
            }else{
                this.tableData = rowsData
            }
            $('#'+options.table.tableId).next().remove();
            this.renderTable(this.tableData,treeObj);
        }
        //删除选中的表格行
        ,removeRow(treeObj){
            let _self = this
                ,options = _self.options
                ,$table = $('#'+options.table.tableId) && $('#'+options.table.tableId).next()
            if(!$table[0]){return;}
            let $firstTds = $table.find('.shuttle-table-body').find('tr').find('td:first')
            ,$tbodyCheckeds = $firstTds.find('.shuttle-checkbox:checked')
            ,delNode = function(nodeId){
                let tableData = _self.tableData;
                for(let i=0;i<tableData.length;i++){
                    let data = tableData[i]
                    if(data[options.table.removeKey] == nodeId){
                        tableData.splice(i,1);
                    }
                }
            }
            $tbodyCheckeds.each(function() {
                let nodeId = $(this).val()
                ,keyId = options.table.removeKey
                ,treeNode = treeObj.getNodeByParam(keyId,nodeId);
                treeObj.checkNode(treeNode, false, true);
                $(this).closest('tr').remove();
                delNode(treeNode[keyId]);
            });
            $table.find('.shuttle-table-head').find('.shuttle-checkbox').prop('checked',false);
            $table.find('.shuttle-table-head').find('.shuttle-show-checkbox').find('.shuttle-icon').removeClass('shuttle-icon-ok')
        }
        //渲染表格
        ,renderTable(rowsData,treeObj){
            let options = this.options
            ,cols = options.table.cols
            ,tableId = options.table.tableId
            if(cols.length<=0){return;}
            let height = ' style="height:auto"',setHeight = options.table.height
            if(/^([0-9]+px|0)$/.test(setHeight)){
                height = ' style="height:'+setHeight+'"'
            }
            if(/^full-([0-9]+)$/.test(setHeight)){
                let num = setHeight.match(/^full-([0-9]+)$/)[1]
                height = 'calc(100% - '+num+'px)'
                height = ' style="height:'+height+'"'
            }
            let html = '<div class="shuttle-table">'
            html+= '<div class="shuttle-table-scroll">'
            html+= '<div class="shuttle-table-head">'
            html+= '<table style="table-layout: fixed;">'
            html+= '<colgroup>'
            cols.forEach(col=>{
                let style = col.width ? ' style="width:'+col.width+'px"' : ''
                html+= '<col'+style+'>'
            })
            html+= '</colgroup>'
            html+= '<thead class="shuttle-table-thead"><tr>'
            cols.forEach((col,i)=>{
                let content = ''
                    ,align = col.align=='center' ? ' table-cell-center' :''
                if(col.type){
                    if(/^checkbox$/.test(col.type)){
                        content += '<div class="shuttle-cell-checkbox"><input class="shuttle-checkbox" type="checkbox" name="checkoxIndex" value="'+i+'"/>'
                        content += '<div class="shuttle-show-checkbox shuttle-checkall"><label class="shuttle-icon"></label></div>'
                        content += '</div>'
                    }
                }else{
                    content += col.title
                }
                html+= '<th class="shuttle-table-cell'+align+'">'+content+'</th>'
            })
            html+= '</tr></thead>'
            html+='</table>'
            html+='</div>'
            html+= '<div class="shuttle-table-body"'+height+'>'
            html+= '<table style="table-layout: fixed;">'
            html+= '<colgroup>'
            cols.forEach(col=>{
                let style = col.width ? ' style="width:'+col.width+'px"' : ''
                html+= '<col'+style+'>'
            })
            html+= '</colgroup>'
            html+= '<tbody class="shuttle-table-tbody">'
            rowsData.forEach((rowData,i)=>{
                html+='<tr tr-index="'+i+'">'
                cols.forEach(col=>{
                    let content = ''
                        ,align = col.align=='center' ? ' table-cell-center' : ''
                    if(col.type){
                        if(/^checkbox$/.test(col.type)){
                            content += '<div class="shuttle-cell-checkbox"><input class="shuttle-checkbox" type="checkbox" name="checkoxIndex" value="'+(rowData[options.table.removeKey])+'"/>'
                            content += '<div class="shuttle-show-checkbox"><label class="shuttle-icon"></label></div>'
                            content += '</div>'
                        }
                    }else{
                        if(col.template){
                            content += col.template.call(this,rowData,i,treeObj)
                        }else{
                            content += rowData[col.field]
                        }
                    }
                    html+= '<td class="shuttle-table-cell'+align+'">'+content+'</td>'
                })
                html+='</tr>'
            })
            html+= '</tbody>'
            html+= '</table>'
            html+= '</div>'
            html+='</div>'
            html+='</div>'
            $('#'+tableId).after(html);
            let $tableEl = $('#'+tableId).next()
            ,tableBody = $tableEl.find('.shuttle-table-body')[0]
            ,scrollWidth = ShuttleFlow.utils.getScrollWidth(tableBody);
            if(scrollWidth>0){
                $tableEl.find(".shuttle-table-head").find("colgroup").append('<col style="width:'+scrollWidth+'px">')
                $tableEl.find(".shuttle-table-head").find(".shuttle-table-thead").find('tr').append('<th class="shuttle-cell-scrollbar"></th>')
            }
            return true;
        }
        //禁用没有人员的节点的复选框
        ,disableCheckbox(nodes,pNode){
            nodes = nodes.concat();
            let simpleNodesTree = function(nodes,pNode,childName){
                childName = childName || 'children'
                let simpleNodes = [];
                for(let i = 0; i < nodes.length; i++){
                    let node = nodes[i];
                    node.pId = pNode?pNode.id:null;
                    simpleNodes.push(node);
                    getchildNode(node)
                }
                return simpleNodes;
                function getchildNode(node){
                    let childNode = node[childName];
                    if(childNode){
                        simpleNodes = simpleNodes.concat(simpleNodesTree(childNode,node,childName));
                    }
                }
            };
            let getAllParents = function(nodes,node){
                nodes = nodes.concat()
                let allParents = [];
                nodes.forEach((curNode,i)=>{
                    if(curNode.id == node.pId){
                        allParents.push(curNode)
                        nodes.splice(i,1)
                        allParents = allParents.concat(getAllParents(nodes,curNode));
                    }
                })
                return allParents;
            };
            nodes = simpleNodesTree(nodes,null);
            for(let i=0,len=nodes.length; i<len; i++){
                let node = nodes[i];
                node['chkDisabled'] = true;
                if(node.type == '1'){
                    node['chkDisabled'] && delete node['chkDisabled']
                    getAllParents(nodes,node).forEach(node=>{
                        node['chkDisabled'] && delete node['chkDisabled']
                    })
                }
            }
            return nodes;
        }
        //设置icon
        , setIcon() {
            let _self = this
            let options = _self.options
            //使用内部自定义icon
            if(options.useCusIcon){
                //开启内部图标时，又指定了dataFilter,
                //则，将其清空
                options.ztree.async.dataFilter = function(treeId, parNode, nodes){
                    let nodesData = []
                        ,treeObj = $.fn.zTree.getZTreeObj(treeId);
                    typeof nodes == 'object' && (nodesData.push(nodes),nodes = nodesData)
                    //跟换图标
                    let set = function(nodes,pId){
                        pId = pId ? pId:null;
                        for(let i = 0,nodeLen = nodes.length; i < nodeLen; i++){
                            let node = nodes[i];
                            if(!pId){
                                node.icon = options.contextPath+'/plugins/layui/modules/shuttleflow/img/company.png'
                                node.open = true;
                            }else{
                                if(node.type != undefined && node.type == 0){
                                    node.icon = options.contextPath+'/plugins/layui/modules/shuttleflow/img/depart.png'
                                }
                            }
                            if(node.children && node.children.length>0){
                                set(node.children,node.id)
                            }
                        }
                    };
                    set(nodes);
                    return ShuttleFlow.utils.parentSubTree(_self.disableCheckbox(nodes));
                };
            }else{
                typeof options.useCusIcon == 'function' && (options.ztree.async.dataFilter = options.useCusIcon)
            }
            return ;
        }
        //关闭loading动画
        ,closeLoading(){
            this.options.isEnableLoading && $(".shuttle-flow-loading").fadeOut(300).remove();
        }
        //异步加载成功后
        ,setAsyncSuc(){
            let _self = this
            ,options = _self.options
            ,ztree = options.ztree
            ,utils = ShuttleFlow.utils
            if(!ztree.callback.onAsyncSuccess && options.isEnableLoading){
                ztree.callback.onAsyncSuccess = function(e, treeId, treeNode, nodes){
                    _self.closeLoading();
                }
            }else{
                if(options.isEnableLoading){
                    let pubSub = utils.pubSubObj()
                    //订阅事件
                    pubSub.subscribe('closeLoadAni',function(){
                        _self.closeLoading()
                    })
                }
            }
        }
        //选中节点时，勾选复选框
        ,setClick(){
            let _self = this
            ,options = _self.options
            ,ztree = options.ztree
            if(!ztree.callback.onClick){
                ztree.callback.onClick = function (e, treeId, treeNode) {
                    e.preventDefault();
                    let treeObj = $.fn.zTree.getZTreeObj(treeId);
                    let status = treeNode.checked;
                    treeObj.checkNode(treeNode, !status, true);
                    //不在选中状态
                    if(status){
                        if(Array.isArray(_self.tableData) && _self.tableData.length>0){
                            let indexOf = _self.tableData.indexOf(treeNode)
                            if(indexOf > -1){
                                _self.tableData.splice(indexOf,1)
                            }
                        }
                    }
                }
            }
        }
        ,setCheck(){
            let _self = this
            ,options = _self.options
            ,ztree = options.ztree
            if(!ztree.callback.onCheck){
                ztree.callback.onCheck = function (e, treeId, treeNode) {
                    e.preventDefault();
                    let status = treeNode.checked;
                    //不在选中状态
                    if(!status) {
                        if (Array.isArray(_self.tableData) && _self.tableData.length > 0) {
                            let indexOf = _self.tableData.indexOf(treeNode)
                            if (indexOf > -1) {
                                _self.tableData.splice(indexOf, 1)
                            }
                        }
                    }
                }
            }
        }
        //模糊查询
        ,fuzzySearch(){
            let options = this.options
            , searchInput = options.searchInput;
            //初始化模糊搜索方法
            if(searchInput.enable){
                ShuttleFlow.utils.fuzzySearch(options.ztree.treeId,'#'+searchInput.id,false,false);
            }
        }
    }
    return ShuttleFlow;
});